﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Lapas.Controls;
using System.Globalization;
using System.IO;
using System.Reflection;



namespace Lapas.Common.Forms
{
    public class EditForm : Lapas.Common.Forms.BaseForm
    {
        #region Properties
        /// <summary>
        /// Chứa đối tượng Edit
        /// </summary>
        public Object EditObject { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public List<Control> RequiredControlList { get; set; }
        #endregion

        private bool _reload;
        /// <summary>
        /// Bien dung de xac dinh co phai bind lai du lieu khong
        /// </summary>
        public bool Reload
        {
            get { return _reload; }
            set { _reload = value; }
        }
	
        protected EditForm()
        {
            InitializeComponent();
            this.OnFormActionChanged += new EventHandler(EditPage_OnFormActionChanged);
            ShowUpdateSuccessMessage = true;
            CloseFormAfterUpdate = true;
        }
        /// <summary>
        /// Used to control form state
        /// </summary>
        public enum EditFormAction
        {
            None,
            View,
            Insert,
            InsertCycle,
            Change,
            Delete,
            Print,
            Filter
        }

        #region abstract methods

        /// <summary>
        /// The methods below define a contract that the derived form must follow
        /// </summary>
        protected virtual bool DoCreate()
        {
            return false;
        }
        protected virtual bool DoUpdate()
        {
            return false;
        }
        protected virtual void BindData()
        {
            if (FormAction != EditFormAction.Insert)
                if (EditObject != null)
                {
                    foreach (Control c in Controls)
                        if ((c.GetType() != typeof(Gui.Wizard.Header)) && (c.GetType() != typeof(Gui.Wizard.InfoPage)))
                            SetControlValue(c);
                }
 
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected virtual bool GetDataFromEditObject()
        {
            if (EditObject != null)
            {
                if (RequiredControlList != null)
                {
                    if (!CheckRequiredFields())
                        return false;
                }
                try
                {
                    foreach (Control c in Controls)
                        if ((c.GetType() != typeof(Gui.Wizard.Header)) && (c.GetType() != typeof(Gui.Wizard.InfoPage)))
                            GetValues(c);
                    return true;
                }
                catch (SbsUIException uiEx)
                {
                    if (uiEx.UIControl != null)
                    {
                        uiEx.UIControl.Focus();
                        SetError(uiEx.UIControl, uiEx.Message);
                    }
                }
            }
            else
            {
                throw new LapasException("Chưa khởi tạo đối tượng EditObject");
            }
            return false;
        }

        bool dataChanged;
        bool enableInsertCycle = true;



        private Button _okButton;
        protected StatusStrip statusStrip;
        protected ToolStripStatusLabel editStatusLabel;
       // private IContainer components;

        public Button OkButton
        {
            get { return _okButton; }
            set { _okButton = value; }
        }

        private Button _closeButton;

        public Button CloseButton
        {
            get { return _closeButton; }
            set { _closeButton = value; }
        }
	
	
        /// <summary>
        /// This event is gonna to notify when the form action is changed. The derived
        /// class can register this event to perform apropriate action
        /// </summary>
        public event EventHandler OnFormActionChanged;
        #endregion
        
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

           
            //InitializeComponent();

            if (FormAction == EditFormAction.Insert)
            {
                this.Icon = Icons.newEditFormIcon;
            }
            else
            {
                this.Icon = Icons.editEditFormIcon;
            }
            //_editFormErrorProvider = new ErrorProvider();

            
            if (this.OkButton != null)
            {
                this.OkButton.Click += new EventHandler(OkButton_Click);
                this.OkButton.Width = 80;
            }

            if (this.CloseButton!= null)
            {
                //Set text Close để đồng bộ
                this.CloseButton.Text = "Đóng lại (&X)";
                this.CloseButton.Click += new EventHandler(closeButton_Click);
            }

            // Xu ly su kien data change o form tai day
            //this.OnFormActionChanged += new EventHandler(EditPage_OnFormActionChanged);

            HandleTextChanged();
            BindData();

            
        }

        

        private void HandleTextChanged()
        {
            
            foreach (Control control in Controls)
            {
                if (control != null)
                {
                    Control childControl = control.GetNextControl(control, true);
                    while (childControl != null)
                    {                      
                        FindMatchControl(childControl);
                        
                        childControl = control.GetNextControl(childControl, true);
                    }

                    FindMatchControl(control);
                   
                }
            }
        }

        private void FindMatchControl(Control control)
        {
            TextBox tempTextBox;
            CheckBox tempCheckBox;
            MaskedTextBox tempMaskedTextBox;
            ComboBox tempComboBox;
            StockTextBox tempStockTextBox;
            NullableDateTimePicker tempNullableDateTimePicker;
            
            // Operator with control
            if (control.GetType() == typeof(TextBox))
            {
                tempTextBox = (TextBox)control;
                tempTextBox.TextChanged += new EventHandler(EditForm_TextChanged);
            }
            if (control.GetType() == typeof(CheckBox))
            {
                tempCheckBox = (CheckBox)control;
                tempCheckBox.CheckStateChanged += new EventHandler(EditForm_TextChanged);
                 
            }
            else if (control.GetType() == typeof(MaskedTextBox))
            {
                tempMaskedTextBox = (MaskedTextBox)control;
                tempMaskedTextBox.TextChanged += new EventHandler(EditForm_TextChanged);
            }
            else if (control.GetType() == typeof(StockTextBox))
            {
                tempStockTextBox = (StockTextBox)control;
                tempStockTextBox.TextChanged += new EventHandler(EditForm_TextChanged);
                tempStockTextBox.LostFocus += new EventHandler(EditForm_TextChanged);
            }
            else if (control.GetType() == typeof(ComboBox))
            {
                tempComboBox = (ComboBox)control;
                tempComboBox.SelectedIndexChanged += new EventHandler(EditForm_TextChanged);
            }
            else if (control.GetType() == typeof(NullableDateTimePicker))
            {
                tempNullableDateTimePicker = (NullableDateTimePicker)control;
                tempNullableDateTimePicker.TextChanged+= new EventHandler(EditForm_TextChanged);
            }
        }

        void EditForm_TextChanged(object sender, EventArgs e)
        {
            this.dataChanged = true;
        }

        /// <summary>
        /// This is the default handler for the event form action changed which
        /// changes the button text appropriately
        /// </summary>
        protected virtual void EditPage_OnFormActionChanged(object sender, EventArgs e)
        {
            editStatusLabel.Text = string.Empty;
            Button okButton = this.OkButton;
            if (okButton != null )
            {
                switch (this.FormAction)
                {                    
                    case EditFormAction.InsertCycle:
                        okButton.Text = "Cập nhật (&M)";
                        break;
                    case EditFormAction.Change:
                        base.AllowBindDefaultForm = false;
                        okButton.Text = "Cập nhật (&M)";
                        break;

                    case EditFormAction.Insert:
                        okButton.Text = "Tạo mới (&M)";
                        if (base.AllowBindDefaultForm) { base.BindDefaultForm(); }
                        break;

                    case EditFormAction.View:
                        okButton.Visible = false;
                        //Khong cho phep xoa du lieu
                        base.BindReadOnlyForm();
                        base.AllowBindDefaultForm = false;
                        break;
                }
            }
        }

        void closeButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        void OkButton_Click(object sender, EventArgs e)
        {
            this.OnDataSave();
        }

        /// <summary>
        /// cho phép đóng form 
        /// </summary>
        private bool closeFormAfterUpdateOrInsert=false;

        public bool CloseFormAfterUpdateOrInsert
        {
            get { return closeFormAfterUpdateOrInsert; }
            set { closeFormAfterUpdateOrInsert = value; }
        }

        /// <summary>
        /// Thuộc tính này sử dụng cho phép hiện message sau khi cập nhật thành công hay không?
        /// </summary>
        public bool ShowUpdateSuccessMessage { get; set; }

        /// <summary>
        /// Thuộc tính cho phép đóng form sau khi update hay không?
        /// </summary>
        public bool CloseFormAfterUpdate { get; set; }

        protected virtual bool OnDataSave()
        {
            bool success = true;
            switch (this.FormAction)
            {
                case EditFormAction.View:
                    this.Close();
                    break;

                case EditFormAction.Insert:
                    success = DoCreate();
                    if (success)
                    {
                        
                        //change form action and raise the event                        
                        if (this.EnableInsertCycle)
                        {
                            this.FormAction = EditFormAction.InsertCycle;
                            this.DataChanged = false;
                        }
                        else
                        {
                            this.FormAction = EditFormAction.Change;
                        }
                        editStatusLabel.Text = "Tạo mới thành công";
                        
                        //Set reload to true
                        _reload = true;
                        //OkButton.Enabled = false;
                        if (closeFormAfterUpdateOrInsert) { this.Close(); }
                    }
                    break;

                case EditFormAction.InsertCycle:
                    bool actionChanged = true;
                    bool display = false;
                    if (this.DataChanged)
                    {
                        actionChanged = success = DoUpdate();
                        if (success) display = true;
                    }
                    if (actionChanged)
                    {
                        //change form action and raise the event
                        this.FormAction = EditFormAction.Insert;
                        
                    }

                    if (display) editStatusLabel.Text = "Cập nhật thành công";
                    //OkButton.Enabled = false;
                    break;

                case EditFormAction.Change:
                    if (this.DataChanged)
                    {
                        success = DoUpdate();
                        if (success)
                        {
                            //if (success) editStatusLabel.Text = "Cập nhật thành công";
                            // OkButton.Enabled = false;
                            //if (closeFormAfterUpdateOrInsert) { this.Close(); }
                            _reload = true;
                            //Hiển thị thông báo
                            if (ShowUpdateSuccessMessage)
                            {
                                DisplayMessage.ShowNotice("Cập nhật thành công !");
                            }

                            if (CloseFormAfterUpdate)
                            {
                                this.Close();
                            }
                        }
                        else
                        {
                            editStatusLabel.Text = "Lỗi cập nhật dữ liệu";
                        }
                    }
                    break;
            }
           
            return success;
        }

        // TODO: Kiem soat truong hop du lieu thay doi
        //protected override void OnFormClosing(FormClosingEventArgs e)
        //{
        //    //if (this.DataChanged)
        //    //{
        //    //    if (!DisplayMessage.ShowConfirm("Dữ liệu có thay đổi.\nBạn có chắc chắn thoát mà không ghi lại dữ liệu?"))
        //    //    {
        //    //        e.Cancel=true;
        //    //        return;
        //    //    }
        //    //}

        //    //base.OnFormClosing(e);
        //}

        //protected virtual void RaiseError(Control control, string message)
        //{
        //    DisplayMessage.ShowError(message);
        //    EditFormErrorProvider.SetError(control, message);            
        //}

        private EditFormAction _formAction; 

        public EditFormAction FormAction
        {
            get
             {
                return _formAction;
            }
            set
            {
                EditFormAction action = this.FormAction;
                _formAction = value;

                if (this.OnFormActionChanged != null && action != value)
                {
                    // Raise event
                    this.OnFormActionChanged(this, EventArgs.Empty);
                }
                
            }
        }

        protected bool DataChanged
        {
            get { return this.dataChanged; }
            set { this.dataChanged = value; }
        }
        
       

        protected bool EnableInsertCycle
        {
            get { return this.enableInsertCycle; }
            set { this.enableInsertCycle = value; }
        }

        //private ErrorProvider _editFormErrorProvider;

        //protected ErrorProvider EditFormErrorProvider
        //{
        //    get { return _editFormErrorProvider; }
        //    set { _editFormErrorProvider = value; }
        //}

        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(EditForm));
            this.statusStrip = new System.Windows.Forms.StatusStrip();
            this.editStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
            this.statusStrip.SuspendLayout();
            this.SuspendLayout();
            // 
            // statusStrip
            // 
            this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.editStatusLabel});
            this.statusStrip.Location = new System.Drawing.Point(0, 251);
            this.statusStrip.Name = "statusStrip";
            this.statusStrip.Size = new System.Drawing.Size(292, 22);
            this.statusStrip.TabIndex = 100;
            // 
            // editStatusLabel
            // 
            this.editStatusLabel.Name = "editStatusLabel";
            this.editStatusLabel.Size = new System.Drawing.Size(0, 17);
            // 
            // EditForm
            // 
            this.ClientSize = new System.Drawing.Size(292, 273);
            this.Controls.Add(this.statusStrip);
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.KeyPreview = true;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "EditForm";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.statusStrip.ResumeLayout(false);
            this.statusStrip.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

        }


        #region Private


        /// <summary>
        /// 
        /// </summary>
        /// <param name="c"></param>
        private void SetControlValue(Control c)
        {
            if (c.HasChildren)
            {
                foreach (Control child in c.Controls)
                    if ((child.GetType() != typeof(Gui.Wizard.Header)) && (child.GetType() != typeof(Gui.Wizard.InfoPage)))
                        SetControlValue(child);
            }
            else
            {
                object value = GetValueFromObject(EditObject, GetFullPropertyName(c));
                if (value != null)
                    SetSpecificControlValue(c, value);

            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="control"></param>
        /// <param name="value"></param>
        protected static void SetSpecificControlValue(Control control, object value)
        {
            if ((control.GetType() == typeof(TextBox)) || (control.GetType() == typeof(MaskedTextBox))
                || (control.GetType() == typeof(StockTextBox)))
            {
                control.Text = Convert.ToString(value, CultureInfo.CurrentCulture);
            }
            else if (control.GetType() == typeof(Label))
            {
                decimal d;
                if (decimal.TryParse(Convert.ToString(value, CultureInfo.CurrentCulture), out d))
                    control.Text = d.ToString("N0", CultureInfo.CurrentCulture);
                else
                    control.Text = Convert.ToString(value, CultureInfo.CurrentCulture);
            }
            else if (control.GetType() == typeof(CheckBox))
            {
                ((CheckBox)control).Checked = Convert.ToBoolean(value, CultureInfo.CurrentCulture);
            }
            else if (control.GetType() == typeof(ComboBox))
            {
                ComboBox cmb = (ComboBox)control;
                if (cmb.Items.Count > 0)
                    cmb.SelectedValue = value;
            }
            else if (control.GetType() == typeof(DateTimePicker))
            {
                DateTime d = Convert.ToDateTime(value, CultureInfo.CurrentCulture);
                if (d != DateTime.MinValue)
                    ((DateTimePicker)control).Value = d;
            }
            else if (control.GetType() == typeof(NullableDateTimePicker))
            {
                DateTime d = Convert.ToDateTime(value, CultureInfo.CurrentCulture);
                if (d != DateTime.MinValue)
                    ((NullableDateTimePicker)control).Value = d;
            }
            else if (control.GetType() == typeof(PictureBox))
            {
                ((PictureBox)control).Image = Image.FromStream(new MemoryStream((byte[])value));
            }
            else
            {
                try
                {
                    control.Text = Convert.ToString(value, CultureInfo.CurrentCulture);
                }
                catch
                { }

            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="EditObject"></param>
        /// <param name="propName"></param>
        /// <returns></returns>
        private object GetValueFromObject(object EditObject, string propName)
        {
            if (EditObject != null)
            {
                if (propName.Contains("_"))
                {
                    string parentPropName = propName.Split(new char[] { '_' })[0];
                    PropertyInfo parProp = EditObject.GetType().GetProperty(parentPropName);
                    if (parProp != null)
                        return GetValueFromObject(parProp.GetValue(EditObject, null), propName.Substring(propName.IndexOf("_", StringComparison.Ordinal) + 1));
                }
                else
                {
                    PropertyInfo propInfo = EditObject.GetType().GetProperty(propName);
                    if (propInfo != null)
                        return propInfo.GetValue(EditObject, null);
                }
            }
            return null;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="c"></param>
        private void GetValues(Control c)
        {
            if (c.HasChildren)
            {
                foreach (Control child in c.Controls)
                    if ((child.GetType() != typeof(Gui.Wizard.Header)) && (child.GetType() != typeof(Gui.Wizard.InfoPage)))
                        GetValues(child);
            }
            else
            {
                GetSpecificValue(EditObject, GetFullPropertyName(c), c);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="targetObject"></param>
        /// <param name="propName"></param>
        /// <param name="c"></param>
        private void GetSpecificValue(object targetObject, string propName, Control c)
        {
            if (targetObject != null)
                if (propName.Contains("_"))
                {
                    string parentPropName = propName.Split(new char[] { '_' })[0];
                    PropertyInfo parProp = targetObject.GetType().GetProperty(parentPropName);
                    if (parProp != null)
                        GetSpecificValue(parProp.GetValue(targetObject, null), propName.Substring(propName.IndexOf("_", StringComparison.Ordinal) + 1), c);
                }
                else
                {
                    PropertyInfo propertyInfo = targetObject.GetType().GetProperty(propName);
                    if (propertyInfo != null)
                    {
                        object value = null;

                        if (c.GetType() != typeof(PictureBox))
                        {
                            value = GetControlValue(c);

                        }
                        else
                        {
                            PictureBox pictureBox = (PictureBox)c;
                            if (pictureBox.Image != null)
                            {
                                using (MemoryStream imgStream = new MemoryStream())
                                {
                                    try
                                    {
                                        pictureBox.Image.Save(imgStream, System.Drawing.Imaging.ImageFormat.Bmp);
                                        value = imgStream.ToArray();

                                    }
                                    catch { value = null; }
                                }
                            }
                        }
                        if (value != null)
                        {
                            try
                            {
                                ReflectorHelper.SetPropertyValue(targetObject, propName, value);
                            }
                            catch (Exception ex)
                            {
                                SbsUIException UIEx = new SbsUIException(string.Format(CultureInfo.InvariantCulture, "Giá trị nhập không hợp lệ. Chi tiết: {0}", ex.Message));
                                UIEx.UIControl = c;
                                throw UIEx;
                            }
                        }
                    }
                }
        }


        private static string GetFullPropertyName(Control c)
        {
            if (!string.IsNullOrEmpty(c.Name))
            {
                char[] nameChars = c.Name.ToCharArray();
                int pos = 0;
                while ((pos < nameChars.Length) && (!nameChars[pos].ToString().Equals(nameChars[pos].ToString().ToUpper(CultureInfo.InvariantCulture))))
                    pos++;
                return c.Name.Substring(pos);
            }
            else
                return string.Empty;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        private static object GetControlValue(Control control)
        {
            if ((control.GetType() == typeof(TextBox)) || (control.GetType() == typeof(MaskedTextBox)))
            {
                return control.Text;
            }
            else if (control.GetType() == typeof(CheckBox))
            {
                return ((CheckBox)control).Checked;
            }
            else if (control.GetType() == typeof(ComboBox))
            {
                return ((ComboBox)control).SelectedValue;
            }
            else if (control.GetType() == typeof(DateTimePicker))
            {
                return ((DateTimePicker)control).Value;
            }
            else if (control.GetType() == typeof(StockTextBox))
            {
                return ((StockTextBox)control).NumericValue;
            }
            else if (control.GetType() == typeof(NullableDateTimePicker))
            {
                return ((NullableDateTimePicker)control).Value;
            }
            else
            {
                return control.Text;
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="control"></param>
        /// <param name="errMsg"></param>
        protected void SetError(Control control, string errMsg)
        {
            RaiseError(control, errMsg);
            Control prCtrl = control.Parent;
            while (prCtrl != null)
            {
                if (prCtrl.GetType() == typeof(TabPage))
                {
                    ((prCtrl as TabPage).Parent as TabControl).SelectedTab = prCtrl as TabPage;
                    prCtrl = null;
                }
                else
                    prCtrl = prCtrl.Parent;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private bool CheckRequiredFields()
        {
            BaseFormErrorProvider.Clear();
            foreach (Control c in RequiredControlList)
                if (!CheckRequiredValue(c))
                    return false;
            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        private bool CheckRequiredValue(Control control)
        {
            bool result = false;
            #region check value by type
            if (control.GetType() == typeof(TextBox))
            {
                result = !string.IsNullOrEmpty(((TextBox)control).Text);
            }
            else if (control.GetType() == typeof(MaskedTextBox))
            {
                result = !string.IsNullOrEmpty(((MaskedTextBox)control).Text);
            }
            else if (control.GetType() == typeof(ComboBox))
            {
                result = ((ComboBox)control).SelectedValue != null;
            }
            else if (control.GetType() == typeof(DateTimePicker))
            {
                result = ((DateTimePicker)control).Value != null;
            }
            else if (control.GetType() == typeof(StockTextBox))
            {
                result = ((StockTextBox)control).NumericValue != null;
            }
            else if (control.GetType() == typeof(NullableDateTimePicker))
            {
                result = ((NullableDateTimePicker)control).Value != null;
            }
            else
            {
                try { result = !string.IsNullOrEmpty(control.Text); }
                catch
                {
                    throw new NotSupportedException(control.Name);
                }
            }
            #endregion
            if (!result)
            {
                SetError(control, "Không được để trống");
                control.Focus();
            }
            return result;
        }

        #endregion
    }
}

